package com.galfins.gogpsextracts.Bds;

import android.location.Location;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.galfins.gogpsextracts.Ephemeris;
import com.galfins.gogpsextracts.EphemerisResponse;
import com.galfins.gogpsextracts.GnssEphemeris;
import com.galfins.gogpsextracts.Iono;
import com.galfins.gogpsextracts.KeplerianModel;
import com.galfins.gogpsextracts.NavigationProducer;
import com.galfins.gogpsextracts.SatellitePosition;

import java.util.ArrayList;

import static com.galfins.gogpsextracts.GetEphFromIgmas.GetBDSEphUrl;
import static com.galfins.gogpsextracts.GetEphFromIgmas.httpGet;

public class RinexNavigationBds implements NavigationProducer {
    RinexNavigationParserBds m_rnp = null;
    long m_ephTimestamp = 0;

    /**
     * Compute the GPS satellite coordinates
     * <p>
     * INPUT:
     *
     * @param unixTime           = time of measurement reception - UNIX        [milliseconds]
     * @param range              = pseudorange measuremnent                          [meters]
     * @param satID              = satellite ID
     * @param satType            = satellite type indicating the constellation (E: Galileo,
     *                           G: GPS)
     * @param receiverClockError = 0.0
     */
    public SatellitePosition getSatPositionAndVelocities(long unixTime, double range, int satID, char satType, double receiverClockError) {

        //long unixTime = obs.getRefTime().getMsec();
        //double range = obs.getSatByIDType(satID, satType).getPseudorange(0);

        RinexNavigationParserBds rnp = getRNPByTimestamp(unixTime);

        if (rnp == null)
            return null;

        if (rnp.findEph(unixTime, satID, satType).getRootA() < 4500)
            return null;

        if (rnp != null) {
            if (rnp.isTimestampInEpocsRange(unixTime)) {
                return rnp.getSatPositionAndVelocities(unixTime, range, satID, satType, receiverClockError);
            } else {
                return null;
            }
        }

        return null;
    }

    protected RinexNavigationParserBds getEph() {
        ArrayList<GnssEphemeris> ephList = new ArrayList<GnssEphemeris>();
        Ephemeris.IonosphericModelProto.Builder ionoBuilder = Ephemeris.IonosphericModelProto.newBuilder();

        RinexNavigationParserBds rnp = null;
        String str = httpGet(GetBDSEphUrl);
        JSONObject object = JSON.parseObject(str);
        if (object != null) {
            m_ephTimestamp = object.getLong("timestamp");

            JSONObject iono = object.getJSONObject("iono");

            ionoBuilder.addAlpha(iono.getDouble("alpha0"));
            ionoBuilder.addAlpha(iono.getDouble("alpha1"));
            ionoBuilder.addAlpha(iono.getDouble("alpha2"));
            ionoBuilder.addAlpha(iono.getDouble("alpha3"));

            ionoBuilder.addBeta(iono.getDouble("beta0"));
            ionoBuilder.addBeta(iono.getDouble("beta1"));
            ionoBuilder.addBeta(iono.getDouble("beta2"));
            ionoBuilder.addBeta(iono.getDouble("beta3"));

            Ephemeris.IonosphericModelProto ionoProto = ionoBuilder.build();
            Ephemeris.IonosphericModelProto ionoProto2 = ionoBuilder.build();

            JSONArray ephArray = object.getJSONArray("eph");

            for (int i = 0; i < ephArray.size(); ++i) {
                BdsEphemeris.Builder builder = BdsEphemeris.newBuilder();

                JSONObject eph = ephArray.getJSONObject(i);

                builder.setSvid(eph.getInteger("prn"));

                builder.setIode(eph.getInteger("iode"));

                builder.setIodc(eph.getInteger("iodc"));

                builder.setAccuracyM(eph.getDouble("ura"));

                builder.setAf0S(eph.getDouble("af0"));

                builder.setAf1SecPerSec(eph.getDouble("af1"));

                builder.setAf2SecPerSec2(eph.getDouble("af2"));

                KeplerianModel.Builder model = KeplerianModel.newBuilder();

                model.setCrs(eph.getDouble("crs"));

                model.setDeltaN(eph.getDouble("deltaN"));

                model.setM0(eph.getDouble("m0"));

                model.setCuc(eph.getDouble("cuc"));

                model.setEccentricity(eph.getDouble("e"));

                model.setCus(eph.getDouble("cus"));

                model.setSqrtA(eph.getDouble("sqrtA"));

                model.setCic(eph.getDouble("cic"));

                model.setOmega0(eph.getDouble("omgea0"));

                model.setCis(eph.getDouble("cis"));

                model.setI0(eph.getDouble("i0"));

                model.setCrc(eph.getDouble("crc"));

                model.setOmega(eph.getDouble("omega"));

                model.setOmegaDot(eph.getDouble("omgeaDot"));

                model.setIDot(eph.getDouble("idot"));

                builder.setTgdS(eph.getDouble("tgd"));

                builder.setHealth(eph.getInteger("health"));

                double toeSec = eph.getDouble("toe");
                model.setToeS(toeSec);
                builder.setTocS(toeSec);

                builder.setWeek(eph.getInteger("week"));

                builder.setKeplerianModel(new KeplerianModel(model));

                ephList.add(builder.build());
            }
            EphemerisResponse ephResponse = new EphemerisResponse(ephList, ionoProto, ionoProto2);
            rnp = new RinexNavigationParserBds(ephResponse);
        }
        return rnp;
    }


    protected RinexNavigationParserBds getRNPByTimestamp(long unixTime) {
        if (m_rnp == null)
        {
            m_rnp = getEph();
        }
        return m_rnp;
    }

    /* (non-Javadoc)
     * @see org.gogpsproject.NavigationProducer#getIono(int)
     */
    @Override
    public Iono getIono(long unixTime) {
        RinexNavigationParserBds rnp = getRNPByTimestamp(unixTime);
        if (rnp != null) return rnp.getIono(unixTime);
        return null;
    }

}

